<?php
/**
 * Created by PhpStorm.
 * User: Apple
 * Date: 2018/11/1 0001
 * Time: 14:41
 */
namespace App\WebSocket;

use EasySwoole\Socket\AbstractInterface\ParserInterface;
use EasySwoole\Socket\Client\WebSocket;
use EasySwoole\Socket\Bean\Caller;
use EasySwoole\Socket\Bean\Response;
use App\Utility\BaseEnum;

/**
 * Class WebSocketParser
 *
 * 此类是自定义的 websocket 消息解析器
 * 此处使用的设计是使用 json string 作为消息格式
 * 当客户端消息到达服务端时，会调用 decode 方法进行消息解析
 * 会将 websocket 消息 转成具体的 Class -> Action 调用 并且将参数注入
 *
 * @package App\WebSocket
 */
class WebSocketParser implements ParserInterface
{

    /**
     * decode
     *
     * @param string $raw
     *            客户端原始消息
     * @param WebSocket $client
     *            WebSocket Client 对象
     * @return Caller Socket 调用对象
     */
    public function decode($raw, $client): ?Caller
    {
        
        $loginFd = $client->getFd();    // 解析 客户端原始消息 调用者对象
        $requestObj = new Caller();
        $reqRouts = BaseEnum::REQUEST_GROUTES;
        if (! empty($raw)) {
            $temp = !empty($raw) ? json_decode($raw,TRUE) : FALSE;
            $isHeartFlag = (!empty($temp) && isset($temp['m']) && intval($temp['m']) === 0)  ? TRUE : FALSE;
            // 判断是否来自心跳数据； 心跳包为0
            if ($raw != "" && (in_array($raw, [ "PING", "1"]) || $isHeartFlag === TRUE)) {  // 来自心跳自动请求ABC
                $requestObj->setControllerClass(Index::class);                          // 找不到类时访问默认Index类
                $requestObj->setAction('index');

                // 设置被调用的Args
                $argslist = ['m' =>-1,'d'=>FALSE,"localUrls"=>['index','index']];
                $requestObj->setArgs($argslist);
                BaseEnum::Logger("---Parse-Control---->parse 为心跳： data=". $raw,'user-login');
            } else {
                
                $controllerPath = '\\App\\GameService\\';                
                // =========================正常处理JSON数据===============================//
                $argRes = json_decode("{$raw}", true);
                $hanldExVal = isset($argRes['m']) ? $argRes['m'] : FALSE; // 协议编码
                $hanldExNum = (isset($hanldExVal) && $hanldExVal !== FALSE && substr("{$hanldExVal}", 0, 2) == '0x') ? hexdec($hanldExVal) : intval($hanldExVal); // 16进制转成10进制操作；
                if (json_last_error() > 0) {
                    BaseEnum::Logger("解析JSON格式出错：Parse-Control---->parse ： error=" . json_last_error(), 'user-login');
                    return NULL;
                }
                if (! is_array($argRes) || $hanldExNum <= 0) {
                    BaseEnum::Logger("解析JSON为空：Parse-Control---->parse  data= unknown command ", 'user-login');
                    return NULL;
                }

                // 查询控制器
                $paraUrl = isset($reqRouts[$hanldExNum]) ? $reqRouts[$hanldExNum] : ""; // 查询协议值
                $paraUrls = ! empty($paraUrl) ? explode('-', $paraUrl) : false;
                $reqData = isset($argRes['d']) ? $argRes['d'] : null; // 取数据Data
                $controlName = isset($paraUrls[0]) ? trim($paraUrls[0]) : ""; // 控制器
                $action = (! empty($paraUrls) && isset($paraUrls[1])) ? trim($paraUrls[1]) : "index"; // 方法名
                $control = $controllerPath . ucfirst($controlName);
                BaseEnum::Logger("控制器初始化：Create-onMessage 转10进制的值：{$hanldExNum}  data=" . json_encode([ 'ctrl' => $control, 'act' => $action ]), 'user-login');
                $argslist = ['m' =>$hanldExVal,'d'=>$reqData,"localUrls"=>FALSE];
                if (! empty($controlName) && class_exists($control)) {
                    $requestObj->setControllerClass($control); // 找不到类时访问默认Index类
                    $requestObj->setAction($action);
                    $argslist['localUrls'] = $paraUrls;
                    BaseEnum::Logger('控制器初始化：setArg =' . json_encode($argslist), 'user-login');
                } else {
                    BaseEnum::Logger("控制器初始化:暂无 ： $hanldExVal ， ==> {$hanldExNum}  data=" . json_encode($argslist), 'user-login');
                    return NULL;
                }
                // =========================正常处理数据END==============================//
                $requestObj->setArgs($argslist); // 设置被调用的Args
            }
        }
        if (!$requestObj->getControllerClass()) {
            return NULL;;
        }
        return $requestObj; // 返回请求对象值
    }

    /**
     *  TODO 解析
     * @param Response $response Socket Response 对象
     * @param WebSocket $client  WebSocket Client 对象
     * @return string 发送给客户端的消息
     */
    public function encode(Response $response, $client): ?string
    {
        /**
         * TODO 这里返回响应给客户端的信息
         * TO 这里应当只做统一的encode操作 具体的状态等应当由 Controller处理
         */
        return $response->getMessage();
    }
}
